# == Schema Information
# Schema version: 38
#
# Table name: users
#
#  id                        :integer(11)     not null, primary key
#  login                     :string(255)
#  email                     :string(255)
#  crypted_password          :string(40)
#  salt                      :string(40)
#  created_at                :datetime
#  updated_at                :datetime
#  remember_token            :string(255)
#  remember_token_expires_at :datetime
#  avatar_url                :string(255)
#  blog_url                  :string(255)
#  bio                       :text
#  is_admin                  :boolean(1)
#  is_school_admin           :boolean(1)
#  ref                       :string(255)
#  bio_html                  :text
#  activation_code           :string(40)
#  activated_at              :datetime
#  last_name                 :string(255)
#  first_name                :string(255)
#  gender                    :integer(11)
#  birth                     :date
#  phone                     :string(255)
#  area_id                   :integer(11)
#  privacy                   :integer(11)
#  identified                :boolean(1)
#

require 'digest/sha1'
class User < ActiveRecord::Base
  belongs_to :area
  has_many :submitted_schools, :class_name => 'School', :foreign_key => 'submitor_id', :dependent => :destroy
  has_many :visiteds
  has_many :visited_schools, :through => :visiteds, :class_name => "School", :foreign_key => "user_id", :source => :school, :dependent => :destroy
  has_many :photos, :dependent => :destroy
  has_many :participations
  has_many :events, :through => :participations
  has_many :submitted_events, :class_name => "Event", :foreign_key => "submitor_id", :order => "created_at desc"
  
  has_many :relationships
  has_many :neighbors, :through => :relationships
  
  has_many :event_comments, :dependent => :destroy
  has_many :school_comments, :dependent => :destroy
  has_many :photo_comments, :dependent => :destroy
  
  has_many :moderatorships, :dependent => :delete_all
  has_many :moderated_groups, :through => :moderatorships, :order => "#{Group.table_name}.title"
  
  has_many :group_memberships, :dependent => :delete_all
  has_many :involved_groups, :through => :group_memberships
  
  # Virtual attribute for the unencrypted password
  attr_accessor :password, :old_password

  validates_presence_of     :login, :email
  validates_presence_of     :password,                   :if => :password_required?
  validates_presence_of     :password_confirmation,      :if => :password_required?
  validates_length_of       :password, :within => 4..40, :if => :password_required?
  validates_confirmation_of :password,                   :if => :password_required?

  validates_length_of       :login,    :within => 2..40
  validates_length_of       :email,    :within => 3..100
  validates_uniqueness_of   :email, :case_sensitive => false
  validates_format_of       :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i,
                                    :message => "不是正确的邮件格式",
                                    :if => Proc.new {|u| !u.avatar_url.blank?}
=begin                                    
  validates_format_of       :avatar_url, :with => /^.*(.jpg|.JPG|.gif|.GIF|.png|.PNG)$/,
                                         :message => "图片格式不正确"
=end
  before_save :encrypt_password, :volunteer_identify, :correct_blog_url
  before_create :make_activation_code
  
  
  file_column :avatar_url, :magick => {
                              :geometry => "72x72>",
                              :versions => {"small" => "16x16", "medium" => "32x32", "large" => "48x48"}
                            }
                            
  # prevents a user from submitting a crafted form that bypasses activation
  # anything else you want your user to change should be added here.
  attr_accessible :login, :email, :password, :password_confirmation, :ref,
                  :blog_url, :bio, :bio_html, :avatar_url, :is_admin, :is_school_admin,
                  :last_name, :first_name, :gender, :birth, :phone, :area_id, :privacy, :identified
                  
  format_attribute :bio
=begin  
  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  def self.authenticate(login, password)
    u = find_by_login(login) # need to get the salt
    u && u.authenticated?(password) ? u : nil
  end
=end

  # Activates the user in the database.
  def activate
    @activated = true
    self.activated_at = Time.now.utc
    self.activation_code = nil
    save(false)
  end

  def activated?
    # the existence of an activation code means they have not activated yet
    activation_code.nil?
  end

  # Returns true if the user has just been activated.
  def recently_activated?
    @activated
  end
  
=begin  
  # refactor to @group.moderated_by?(user), see detail in groups_controller.rb
  def moderator_of?(group)
    moderatorships.count("#{Moderatorship.table_name}.id", :conditions =>['group_id=?', (group.is_a?(Group) ? group.id : group)]) == 1
  end
=end
 
  def addable?(user)
    user!=:false && id!=user.id && !user.neighbors.include?(self)
  end
  
  def removeable?(user)
    user!=:false && id!=user.id && user.neighbors.include?(self)
  end
  
  #Authenticate a user by their email and unencrypted password. Returns the user or nil.
  def self.authenticate(email, password)
    u = find :first, :conditions => ['email = ? and activated_at IS NOT NULL', email]
    u && u.authenticated?(password) ? u : nil
  end

  # Encrypts some data with the salt.
  def self.encrypt(password, salt)
    Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  end

  # Encrypts the password with the user salt
  def encrypt(password)
    self.class.encrypt(password, salt)
  end

  def authenticated?(password)
    crypted_password == encrypt(password)
  end

  def remember_token?
    remember_token_expires_at && Time.now.utc < remember_token_expires_at 
  end

  # These create and unset the fields required for remembering users between browser closes
  def remember_me
    remember_me_for 2.weeks
  end

  def remember_me_for(time)
    remember_me_until time.from_now.utc
  end

  def remember_me_until(time)
    self.remember_token_expires_at = time
    self.remember_token            = encrypt("#{email}--#{remember_token_expires_at}")
    save(false)
  end

  def forget_me
    self.remember_token_expires_at = nil
    self.remember_token            = nil
    save(false)
  end
  
  def location
    if area_id.blank?
      "未知"
    else
      self.area.title
    end
  end
  
  def self.archives
    date_func = "extract(year from created_at) as year,extract(month from created_at) as month"
    
    counts = User.find_by_sql(["select count(*) as count, #{date_func} from users where created_at < ? group by year,month order by year asc,month asc",Time.now])
    
    sum = 0
    result = counts.map do |entry|
      sum += entry.count.to_i
      {
        :name => entry.year + "年" + entry.month + "月",
        :month => entry.month.to_i,
        :year => entry.year.to_i,
        :delta => entry.count,
        :sum => sum
      }
    end
    return result.reverse
  end

  protected
    # before filter 
    def encrypt_password
      return if password.blank?
      self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
      self.crypted_password = encrypt(password)
    end
    
    def password_required?
      crypted_password.blank? || !password.blank?
    end
    
    def make_activation_code
      self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
    end
    
    def volunteer_identify
      attrs = %w(first_name last_name gender birth area_id phone privacy)
      self.identified = true
      attrs.each do |a|
        self.identified = false if self.send(a).blank?
      end
    end
    
    def correct_blog_url
      unless self.blog_url.to_s.empty?
        unless self.blog_url =~ /^http\:\/\//
          self.blog_url = "http://#{self.blog_url}"
        end
      end
    end
end
